/*
 * @Author: sonss
 * @Date: 2024-08-26 19:09:42
 * @LastEditTime: 2024-09-04 12:35:42
 * @FilePath: /ss-file-antd/src/pages/Assets/File/index.tsx
 * @Description:  资源文件
 */

import '@/assets/css/assets_file.scss';
import AssetsCategorySelect from '@/components/Form/AssetsCategorySelect';
import ButtonUpload from '@/components/Upload/Button';
import DownZipButton from '@/components/Utils/DownZipButton';
import { SceneEnum, SceneLabelEnum } from '@/enums/assets_file';
import { Remove, Save, Search } from '@/services/assets_file';
import { descSize } from '@/utils/file';
import {
  CloudUploadOutlined,
  FileOutlined,
  LoadingOutlined,
  ShareAltOutlined,
  VideoCameraOutlined,
} from '@ant-design/icons';
import {
  ActionType,
  PageContainer,
  ProCard,
  ProColumns,
  ProFormInstance,
  ProTable,
  TableDropdown,
} from '@ant-design/pro-components';
import { Button, Image, message, Popconfirm, Row, Space, Tag, Tooltip } from 'antd';
import { saveAs } from 'file-saver';
import moment from 'moment';
import { Key, useRef, useState } from 'react';
import { LazyLoadImage } from 'react-lazy-load-image-component';
import 'react-lazy-load-image-component/src/effects/blur.css';
import {
  CreateModule as ShareCreateModule,
  SuccessModule as ShareSuccessModule,
} from '../Share/modules';
import EditModule from './modules/Edit';

const AssetsFileIndexPage: React.FC = () => {
  const table = useRef<ActionType>();
  const form = useRef<ProFormInstance>();
  const [msgApi, msgContextHolder] = message.useMessage();

  const [previewVisible, setPreviewVisible] = useState<boolean>(false);
  const [previewUrl, setPreviewUrl] = useState<string>();
  const [uploadLoading, setUploadLoading] = useState<boolean>(false);
  const [hasUploadError, setHasUploadError] = useState<boolean>(false);
  const [editRecord, setEditRecord] = useState<ASSETS.FILE.Row>();
  const [sharer, setSharer] = useState<ASSETS.FILE.SearchParams>();
  const [shared, setShared] = useState<ASSETS.SHARE.CreateResponse>();
  const [selectKeys, setSelectKeys] = useState<Key[]>([]);

  const refresh = (resetPageIndex?: boolean) => {
    table.current?.reload(resetPageIndex);
  };

  const handleRemove = (record: ASSETS.FILE.Row) => {
    const req: ASSETS.FILE.RemoveForm = {
      ids: [record.id!],
    };
    Remove(req).then((res) => {
      if (res.code !== 0) {
        return;
      }
      refresh();
    });
  };

  const handleDownload = (record: ASSETS.FILE.Row) => {
    fetch(record.fileUrl!)
      .then((res) => res.blob())
      .then((blob) => {
        saveAs(blob, record.fileName || `unknown${record.fileExt ? '.' + record.fileExt : ''}`);
      })
      .catch((error) => {
        msgApi.error('下载出错：' + error);
      });
  };

  const handlePreview = (record: ASSETS.FILE.Row) => {
    setPreviewUrl(record.fileUrl);
    setPreviewVisible(true);
  };

  const edit = (record: ASSETS.FILE.Row) => {
    setEditRecord(record);
  };

  const columns: ProColumns<ASSETS.FILE.Row>[] = [
    {
      dataIndex: 'id',
      title: 'ID',
      search: false,
      width: 100,
      align: 'center',
    },
    {
      dataIndex: 'scene',
      title: '类型',
      valueType: 'select',
      valueEnum: () => {
        const data = new Map();
        SceneLabelEnum.forEach((v: any) => {
          data.set(v.value, {
            text: v.label,
          });
        });
        return data;
      },
      align: 'center',
      width: 50,
      order: 80,
    },
    {
      dataIndex: 'cover',
      title: '封面',
      render: (_, record) => {
        switch (record.scene) {
          case SceneEnum.IMAGE:
            return (
              <div className="assets-cover cursor" onClick={() => handlePreview(record)}>
                <LazyLoadImage src={record.fileUrl} alt={record.fileName} effect="blur" />
              </div>
            );
            break;

          case SceneEnum.MEDIA:
            return (
              <div className="assets-cover">
                <VideoCameraOutlined className="icon-file" />
              </div>
            );
            break;

          default:
            return (
              <>
                <div className="assets-cover">
                  <FileOutlined className="icon-file" />
                </div>
              </>
            );
        }
      },
      align: 'center',
      width: 120,
      search: false,
    },
    {
      dataIndex: 'fileName',
      title: '文件名',
      search: true,
      render: (_, record) => {
        return (
          <>
            <div>{record.fileName}</div>
            <div style={{ color: '#999', fontSize: 12 }}>
              <Row>{record.fileType}</Row>
              <Row>
                {record.tags ? (
                  record.tags
                    .split(/[, ;]+/)
                    .map((label, idx) => <Tag key={`tag_${record.id}_${idx}`}>{label}</Tag>)
                ) : (
                  <span>(无标签)</span>
                )}
              </Row>
            </div>
          </>
        );
      },
      width: '35%',
    },
    {
      dataIndex: 'fileSize',
      title: '文件大小',
      search: false,
      renderText: (_, record) => {
        return descSize(record.fileSize || 0);
      },
      align: 'right',
    },
    {
      dataIndex: 'createTime',
      title: '创建时间',
      search: false,
      renderText: (_, record) => {
        return record.createTime
          ? moment(record.createTime * 1000).format('YY/MM/DD HH:mm')
          : undefined;
      },
      align: 'center',
    },
    {
      title: '选择操作',
      key: 'action',
      valueType: 'option',
      align: 'center',
      render: (_, record) => {
        return (
          <Space>
            <a onClick={() => handleDownload(record)}>下载</a>
            <TableDropdown
              key="more"
              menus={[
                {
                  key: 'edit',
                  name: '修改',
                  onClick: () => edit(record),
                },
                {
                  key: 'del',
                  name: (
                    <Popconfirm
                      key="del"
                      title="确认要删除吗？"
                      onConfirm={() => handleRemove(record)}
                    >
                      <a>删除</a>
                    </Popconfirm>
                  ),
                },
              ]}
            />
          </Space>
        );
      },
    },
    {
      dataIndex: 'rootId',
      key: 'rootId',
      title: '分类',
      valueType: 'treeSelect',
      hideInTable: true,
      renderFormItem: () => {
        return <AssetsCategorySelect />;
      },
      order: 100,
    },
    {
      dataIndex: 'words',
      key: 'words',
      title: '关键词',
      hideInTable: true,
    },
  ];

  const search = async (params: ASSETS.FILE.SearchRequest & BaseRequestParams) => {
    const req: ASSETS.FILE.SearchRequest = { ...params, page: params.current || 1 };
    const res = await Search(req);

    return {
      success: true,
      data: res.data?.list || [],
      total: res.data?.total || 0,
    };
  };

  const handleUploadChange = (file: UPLOADER.FileInfo) => {
    const req: ASSETS.FILE.SaveForm = {
      scene: file.scene,
      fileName: file.fileName,
      fileSize: file.size,
      fileExt: file.ext,
      fileType: file.mimeType,
      filePath: file.filePath,
      fileUrl: file.url,
    };

    // 塞入分类
    (() => {
      const rootId = form.current?.getFieldValue('rootId');
      if (!rootId) {
        return;
      }

      if (Array.isArray(rootId)) {
        if (rootId.length > 0) {
          req.arrCategoryId = rootId;
        }
      } else {
        req.arrCategoryId = [rootId];
      }
    })();

    Save(req).then((res) => {
      if (res.code !== 0) {
        return;
      }
      refresh();
    });
  };

  const handleUploadCancel = () => {
    setUploadLoading(false);
    setHasUploadError(false);
  };

  const handleDownErrr = (err: any) => {
    msgApi.error(err + '' || '未知错误');
  };

  const handleEditClose = () => {
    setEditRecord(undefined);
  };

  const handleEditSuccess = () => {
    refresh();
    handleEditClose();
  };

  const handleSharerClose = () => {
    setSharer(undefined);
  };

  const handleSharerSuccess = (data?: ASSETS.SHARE.CreateResponse) => {
    handleSharerClose();
    setShared(data);
  };

  const handleSharedCoese = () => {
    setShared(undefined);
  };

  const handleShare = () => {
    if (selectKeys.length < 1) {
      msgApi.error('请选择文件');
      return;
    }

    setSharer({
      id: selectKeys.map((v) => v as number),
    });
  };

  const handleRowSelectChange = (keys: Key[]) => {
    setSelectKeys(keys);
  };

  return (
    <>
      <PageContainer title="资源文件">
        <ProCard title="列表">
          <ProTable<ASSETS.FILE.Row, ASSETS.FILE.SearchRequest>
            actionRef={table}
            formRef={form}
            rowKey="id"
            columns={columns}
            request={search}
            search={{
              span: 6,
              defaultCollapsed: false,
            }}
            pagination={{
              defaultPageSize: 20,
            }}
            scroll={{ x: true }}
            toolbar={{
              actions: [
                <Space key="btn:upload">
                  <Tooltip title="上传有错误了！" open={hasUploadError}>
                    <ButtonUpload
                      multiple={true}
                      onChange={handleUploadChange}
                      onLoad={(v) => setUploadLoading(v)}
                      onError={() => setHasUploadError(true)}
                      disabled={uploadLoading}
                      btnTitle="上传"
                      btnChild={
                        <>{uploadLoading ? <LoadingOutlined /> : <CloudUploadOutlined />}</>
                      }
                    />
                  </Tooltip>
                  {hasUploadError && <a onClick={handleUploadCancel}>取消</a>}
                </Space>,
              ],
            }}
            rowSelection={{
              preserveSelectedRowKeys: true,
              onChange: handleRowSelectChange,
            }}
            tableAlertRender={(p) => {
              return (
                <Space size={24}>
                  <span>
                    已选 {p.selectedRowKeys.length} 项
                    <a style={{ marginInlineStart: 8 }} onClick={p.onCleanSelected}>
                      取消选择
                    </a>
                  </span>
                </Space>
              );
            }}
            tableAlertOptionRender={(p) => {
              return (
                <Space size={16}>
                  <Button title="分享" onClick={handleShare}>
                    <ShareAltOutlined />
                  </Button>
                  <DownZipButton
                    size="small"
                    title="下载"
                    files={p.selectedRows.map((v) => {
                      return {
                        url: v.fileUrl!,
                        name: v.fileName,
                      };
                    })}
                    onError={handleDownErrr}
                  />
                </Space>
              );
            }}
          />
        </ProCard>
      </PageContainer>
      <Image
        width={200}
        style={{ display: 'none' }}
        src={previewUrl || PUBLIC_PATH + 'logo.jpeg'}
        preview={{
          visible: previewVisible,
          scaleStep: 0.5,
          src: previewUrl,
          onVisibleChange: (value) => {
            setPreviewVisible(value);
          },
        }}
      />
      {editRecord && (
        <EditModule record={editRecord} onSuccess={handleEditSuccess} onClose={handleEditClose} />
      )}
      {sharer && (
        <ShareCreateModule
          params={sharer}
          onSuccess={handleSharerSuccess}
          onClose={handleSharerClose}
        />
      )}
      {shared && (
        <ShareSuccessModule record={shared} onOk={handleSharedCoese} onCancel={handleSharedCoese} />
      )}
      {msgContextHolder}
    </>
  );
};

export default AssetsFileIndexPage;
